package com.lh.center.common.web.handle;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lh.center.common.base.CommonPage;
import com.lh.center.common.base.PageResponse;
import com.lh.center.common.base.ResponseEntity;
import com.lh.center.common.base.session.SessionUser;
import com.lh.center.common.constant.GlobalConstant;
import com.lh.center.common.exception.CommonException;
import com.lh.center.common.exception.ErrorEnum;
import com.lh.center.common.web.advice.BeforeResponseAdvice;
import com.lh.center.common.web.session.SessionOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 接口数据响应前处理
 */
@Slf4j
@RestControllerAdvice
public class BeforeResponseHandle implements ResponseBodyAdvice {

    protected static final CommonPage EMPTY_PAGE = new CommonPage();
    protected static final Object EMPTY_OBJ = new Object();
    protected static final List<?> EMPTY_ARRAY = Collections.emptyList();

    @Lazy
    @Resource
    private BeforeResponseAdvice beforeResponseAdvice;

    @Lazy
    @Resource
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        Class<?> type = Objects.requireNonNull(returnType.getMethod()).getReturnType();
        return process(body,type, SessionOperation.getRequest());
    }

    public Object process(Object outObj, Class<?> MethodReturnType, HttpServletRequest request) {
        outObj = beforeResponseAdvice.beforePackage(outObj,MethodReturnType);
        if(!SessionOperation.requirePackage()){
            SessionOperation.responseParams.set(JSONUtil.toJsonStr(outObj));
            return outObj;
        }
        ResponseEntity pack = pack(outObj, MethodReturnType, request);
        SessionOperation.responseParams.set(JSONUtil.toJsonStr(pack));
        Object encrypt = encrypt(pack.getPayload());
        pack.setPayload(encrypt);
        return beforeResponseAdvice.afterPackage(outObj, pack);
    }

    /**
     * 对返回数据进行包装
     */
    protected ResponseEntity<?> pack(Object outObj, Class<?> MethodReturnType, HttpServletRequest request){
        if(outObj instanceof ResponseEntity){
            return (ResponseEntity<?>) outObj;
        }
        ResponseEntity<Object> rb = ResponseEntity.success();
        rb.setPayload(outObj);
        if (rb.getPayload() == null) {
            //返回值为空，要判断具体情况
            rb.setPayload(EMPTY_OBJ);
            if (IPage.class.isAssignableFrom(MethodReturnType) || Collection.class.isAssignableFrom(MethodReturnType)) {
                rb.setPayload(EMPTY_ARRAY);
                rb.setPage(EMPTY_PAGE);
            }
            return rb;

        } else if (IPage.class.isAssignableFrom(MethodReturnType)){
            //单独处理分页数据
            Page<?> data = (Page<?>) outObj;
            rb.setPayload(data.getRecords());
            rb.setPage(CommonPage.resolveMp(data));
        } else if (PageResponse.class.isAssignableFrom(MethodReturnType)) {
            PageResponse<?> data = (PageResponse<?>) outObj;
            rb.setPayload(data.getRecords());
            rb.setPage(CommonPage.resolveCustomPageResponse(data));
        }
        //最后进行数据加密
        SessionUser o = (SessionUser) Optional.ofNullable(SessionOperation.getUserNotException()).orElse(new SessionUser());
        return beforeResponseAdvice.afterSecret(outObj, o.getSecret(),rb);
    }

    /**
     * 对返回数据进行加密
     */
    protected Object encrypt(Object outObj){
//        SessionUser user = SessionOperation.getUserNotException();
//        if(user==null || !user.isSecretEnabled()){
//            return outObj;
//        }
//        if(!SessionOperation.toAuth.get()){
//            return outObj;
//        }
//        Set<String> notSecretUri = SessionOperation.getConfiguration().getNotSecretUri();
//        if(!CollectionUtils.isEmpty(notSecretUri)){
//            PathMatcher matcher = new AntPathMatcher();
//            String requestURI = SessionOperation.getRequest().getRequestURI();
//            boolean match = notSecretUri.stream().anyMatch(uri -> matcher.match(uri, requestURI));
//            if(match){
//                return outObj;
//            }
//        }
//        String secret = user.getSecret();
        String enableSecret = SessionOperation.getRequest().getHeader(GlobalConstant.header_enable_secret);
        if(StringUtils.isBlank(enableSecret) || enableSecret.equalsIgnoreCase("false")){
            return outObj;
        }
        String secret = SessionOperation.getRequest().getHeader(GlobalConstant.header_secret_key);
        try {
            AES aes = SecureUtil.aes(secret.getBytes());
            return aes.encryptBase64(objectMapper.writeValueAsString(outObj));
        } catch (Exception e) {
            throw new CommonException(ErrorEnum.aes_encrypt_error);
        }
    }
}
